1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.base;
16  
17  import com.google.common.annotations.GwtCompatible;
18  
19  import javax.annotation.Nullable;
20  
21  /**
22   * Static convenience methods that help a method or constructor check whether it was invoked
23   * correctly (whether its <i>preconditions</i> have been met). These methods generally accept a
24   * {@code boolean} expression which is expected to be {@code true} (or in the case of {@code
25   * checkNotNull}, an object reference which is expected to be non-null). When {@code false} (or
26   * {@code null}) is passed instead, the {@code Preconditions} method throws an unchecked exception,
27   * which helps the calling method communicate to <i>its</i> caller that <i>that</i> caller has made
28   * a mistake. Example: <pre>   {@code
29   *
30   *   /**
31   *    * Returns the positive square root of the given value.
32   *    *
33   *    * @throws IllegalArgumentException if the value is negative
34   *    *}{@code /
35   *   public static double sqrt(double value) {
36   *     Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
37   *     // calculate the square root
38   *   }
39   *
40   *   void exampleBadCaller() {
41   *     double d = sqrt(-1.0);
42   *   }}</pre>
43   *
44   * In this example, {@code checkArgument} throws an {@code IllegalArgumentException} to indicate
45   * that {@code exampleBadCaller} made an error in <i>its</i> call to {@code sqrt}.
46   *
47   * <h3>Warning about performance</h3>
48   *
49   * <p>The goal of this class is to improve readability of code, but in some circumstances this may
50   * come at a significant performance cost. Remember that parameter values for message construction
51   * must all be computed eagerly, and autoboxing and varargs array creation may happen as well, even
52   * when the precondition check then succeeds (as it should almost always do in production). In some
53   * circumstances these wasted CPU cycles and allocations can add up to a real problem.
54   * Performance-sensitive precondition checks can always be converted to the customary form:
55   * <pre>   {@code
56   *
57   *   if (value < 0.0) {
58   *     throw new IllegalArgumentException("negative value: " + value);
59   *   }}</pre>
60   *
61   * <h3>Other types of preconditions</h3>
62   *
63   * <p>Not every type of precondition failure is supported by these methods. Continue to throw
64   * standard JDK exceptions such as {@link java.util.NoSuchElementException} or {@link
65   * UnsupportedOperationException} in the situations they are intended for.
66   *
67   * <h3>Non-preconditions</h3>
68   *
69   * <p>It is of course possible to use the methods of this class to check for invalid conditions
70   * which are <i>not the caller's fault</i>. Doing so is <b>not recommended</b> because it is
71   * misleading to future readers of the code and of stack traces. See
72   * <a href="http://code.google.com/p/guava-libraries/wiki/ConditionalFailuresExplained">Conditional
73   * failures explained</a> in the Guava User Guide for more advice.
74   *
75   * <h3>{@code java.util.Objects.requireNonNull()}</h3>
76   *
77   * <p>Projects which use {@code com.google.common} should generally avoid the use of {@link
78   * java.util.Objects#requireNonNull(Object)}. Instead, use whichever of {@link
79   * #checkNotNull(Object)} or {@link Verify#verifyNotNull(Object)} is appropriate to the situation.
80   * (The same goes for the message-accepting overloads.)
81   *
82   * <h3>Only {@code %s} is supported</h3>
83   *
84   * <p>In {@code Preconditions} error message template strings, only the {@code "%s"} specifier is
85   * supported, not the full range of {@link java.util.Formatter} specifiers.
86   *
87   * <h3>More information</h3>
88   *
89   * <p>See the Guava User Guide on
90   * <a href="http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained">using {@code
91   * Preconditions}</a>.
92   *
93   * @author Kevin Bourrillion
94   * @since 2.0 (imported from Google Collections Library)
95   */
96  @GwtCompatible
97  public final class Preconditions {
98    private Preconditions() {}
99  
100   /**
101    * Ensures the truth of an expression involving one or more parameters to the calling method.
102    *
103    * @param expression a boolean expression
104    * @throws IllegalArgumentException if {@code expression} is false
105    */
106   public static void checkArgument(boolean expression) {
107     if (!expression) {
108       throw new IllegalArgumentException();
109     }
110   }
111 
112   /**
113    * Ensures the truth of an expression involving one or more parameters to the calling method.
114    *
115    * @param expression a boolean expression
116    * @param errorMessage the exception message to use if the check fails; will be converted to a
117    *     string using {@link String#valueOf(Object)}
118    * @throws IllegalArgumentException if {@code expression} is false
119    */
120   public static void checkArgument(boolean expression, @Nullable Object errorMessage) {
121     if (!expression) {
122       throw new IllegalArgumentException(String.valueOf(errorMessage));
123     }
124   }
125 
126   /**
127    * Ensures the truth of an expression involving one or more parameters to the calling method.
128    *
129    * @param expression a boolean expression
130    * @param errorMessageTemplate a template for the exception message should the check fail. The
131    *     message is formed by replacing each {@code %s} placeholder in the template with an
132    *     argument. These are matched by position - the first {@code %s} gets {@code
133    *     errorMessageArgs[0]}, etc.  Unmatched arguments will be appended to the formatted message
134    *     in square braces. Unmatched placeholders will be left as-is.
135    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
136    *     are converted to strings using {@link String#valueOf(Object)}.
137    * @throws IllegalArgumentException if {@code expression} is false
138    * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
139    *     {@code errorMessageArgs} is null (don't let this happen)
140    */
141   public static void checkArgument(boolean expression,
142       @Nullable String errorMessageTemplate,
143       @Nullable Object... errorMessageArgs) {
144     if (!expression) {
145       throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
146     }
147   }
148 
149   /**
150    * Ensures the truth of an expression involving the state of the calling instance, but not
151    * involving any parameters to the calling method.
152    *
153    * @param expression a boolean expression
154    * @throws IllegalStateException if {@code expression} is false
155    */
156   public static void checkState(boolean expression) {
157     if (!expression) {
158       throw new IllegalStateException();
159     }
160   }
161 
162   /**
163    * Ensures the truth of an expression involving the state of the calling instance, but not
164    * involving any parameters to the calling method.
165    *
166    * @param expression a boolean expression
167    * @param errorMessage the exception message to use if the check fails; will be converted to a
168    *     string using {@link String#valueOf(Object)}
169    * @throws IllegalStateException if {@code expression} is false
170    */
171   public static void checkState(boolean expression, @Nullable Object errorMessage) {
172     if (!expression) {
173       throw new IllegalStateException(String.valueOf(errorMessage));
174     }
175   }
176 
177   /**
178    * Ensures the truth of an expression involving the state of the calling instance, but not
179    * involving any parameters to the calling method.
180    *
181    * @param expression a boolean expression
182    * @param errorMessageTemplate a template for the exception message should the check fail. The
183    *     message is formed by replacing each {@code %s} placeholder in the template with an
184    *     argument. These are matched by position - the first {@code %s} gets {@code
185    *     errorMessageArgs[0]}, etc.  Unmatched arguments will be appended to the formatted message
186    *     in square braces. Unmatched placeholders will be left as-is.
187    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
188    *     are converted to strings using {@link String#valueOf(Object)}.
189    * @throws IllegalStateException if {@code expression} is false
190    * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
191    *     {@code errorMessageArgs} is null (don't let this happen)
192    */
193   public static void checkState(boolean expression,
194       @Nullable String errorMessageTemplate,
195       @Nullable Object... errorMessageArgs) {
196     if (!expression) {
197       throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs));
198     }
199   }
200 
201   /**
202    * Ensures that an object reference passed as a parameter to the calling method is not null.
203    *
204    * @param reference an object reference
205    * @return the non-null reference that was validated
206    * @throws NullPointerException if {@code reference} is null
207    */
208   public static <T> T checkNotNull(T reference) {
209     if (reference == null) {
210       throw new NullPointerException();
211     }
212     return reference;
213   }
214 
215   /**
216    * Ensures that an object reference passed as a parameter to the calling method is not null.
217    *
218    * @param reference an object reference
219    * @param errorMessage the exception message to use if the check fails; will be converted to a
220    *     string using {@link String#valueOf(Object)}
221    * @return the non-null reference that was validated
222    * @throws NullPointerException if {@code reference} is null
223    */
224   public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
225     if (reference == null) {
226       throw new NullPointerException(String.valueOf(errorMessage));
227     }
228     return reference;
229   }
230 
231   /**
232    * Ensures that an object reference passed as a parameter to the calling method is not null.
233    *
234    * @param reference an object reference
235    * @param errorMessageTemplate a template for the exception message should the check fail. The
236    *     message is formed by replacing each {@code %s} placeholder in the template with an
237    *     argument. These are matched by position - the first {@code %s} gets {@code
238    *     errorMessageArgs[0]}, etc.  Unmatched arguments will be appended to the formatted message
239    *     in square braces. Unmatched placeholders will be left as-is.
240    * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
241    *     are converted to strings using {@link String#valueOf(Object)}.
242    * @return the non-null reference that was validated
243    * @throws NullPointerException if {@code reference} is null
244    */
245   public static <T> T checkNotNull(T reference,
246       @Nullable String errorMessageTemplate,
247       @Nullable Object... errorMessageArgs) {
248     if (reference == null) {
249       // If either of these parameters is null, the right thing happens anyway
250       throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
251     }
252     return reference;
253   }
254 
255   /*
256    * All recent hotspots (as of 2009) *really* like to have the natural code
257    *
258    * if (guardExpression) {
259    *    throw new BadException(messageExpression);
260    * }
261    *
262    * refactored so that messageExpression is moved to a separate String-returning method.
263    *
264    * if (guardExpression) {
265    *    throw new BadException(badMsg(...));
266    * }
267    *
268    * The alternative natural refactorings into void or Exception-returning methods are much slower.
269    * This is a big deal - we're talking factors of 2-8 in microbenchmarks, not just 10-20%.  (This
270    * is a hotspot optimizer bug, which should be fixed, but that's a separate, big project).
271    *
272    * The coding pattern above is heavily used in java.util, e.g. in ArrayList.  There is a
273    * RangeCheckMicroBenchmark in the JDK that was used to test this.
274    *
275    * But the methods in this class want to throw different exceptions, depending on the args, so it
276    * appears that this pattern is not directly applicable.  But we can use the ridiculous, devious
277    * trick of throwing an exception in the middle of the construction of another exception.  Hotspot
278    * is fine with that.
279    */
280 
281   /**
282    * Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
283    * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
284    *
285    * @param index a user-supplied index identifying an element of an array, list or string
286    * @param size the size of that array, list or string
287    * @return the value of {@code index}
288    * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
289    * @throws IllegalArgumentException if {@code size} is negative
290    */
291   public static int checkElementIndex(int index, int size) {
292     return checkElementIndex(index, size, "index");
293   }
294 
295   /**
296    * Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
297    * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
298    *
299    * @param index a user-supplied index identifying an element of an array, list or string
300    * @param size the size of that array, list or string
301    * @param desc the text to use to describe this index in an error message
302    * @return the value of {@code index}
303    * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
304    * @throws IllegalArgumentException if {@code size} is negative
305    */
306   public static int checkElementIndex(
307       int index, int size, @Nullable String desc) {
308     // Carefully optimized for execution by hotspot (explanatory comment above)
309     if (index < 0 || index >= size) {
310       throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
311     }
312     return index;
313   }
314 
315   private static String badElementIndex(int index, int size, String desc) {
316     if (index < 0) {
317       return format("%s (%s) must not be negative", desc, index);
318     } else if (size < 0) {
319       throw new IllegalArgumentException("negative size: " + size);
320     } else { // index >= size
321       return format("%s (%s) must be less than size (%s)", desc, index, size);
322     }
323   }
324 
325   /**
326    * Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of
327    * size {@code size}. A position index may range from zero to {@code size}, inclusive.
328    *
329    * @param index a user-supplied index identifying a position in an array, list or string
330    * @param size the size of that array, list or string
331    * @return the value of {@code index}
332    * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
333    * @throws IllegalArgumentException if {@code size} is negative
334    */
335   public static int checkPositionIndex(int index, int size) {
336     return checkPositionIndex(index, size, "index");
337   }
338 
339   /**
340    * Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of
341    * size {@code size}. A position index may range from zero to {@code size}, inclusive.
342    *
343    * @param index a user-supplied index identifying a position in an array, list or string
344    * @param size the size of that array, list or string
345    * @param desc the text to use to describe this index in an error message
346    * @return the value of {@code index}
347    * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
348    * @throws IllegalArgumentException if {@code size} is negative
349    */
350   public static int checkPositionIndex(int index, int size, @Nullable String desc) {
351     // Carefully optimized for execution by hotspot (explanatory comment above)
352     if (index < 0 || index > size) {
353       throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
354     }
355     return index;
356   }
357 
358   private static String badPositionIndex(int index, int size, String desc) {
359     if (index < 0) {
360       return format("%s (%s) must not be negative", desc, index);
361     } else if (size < 0) {
362       throw new IllegalArgumentException("negative size: " + size);
363     } else { // index > size
364       return format("%s (%s) must not be greater than size (%s)", desc, index, size);
365     }
366   }
367 
368   /**
369    * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list
370    * or string of size {@code size}, and are in order. A position index may range from zero to
371    * {@code size}, inclusive.
372    *
373    * @param start a user-supplied index identifying a starting position in an array, list or string
374    * @param end a user-supplied index identifying a ending position in an array, list or string
375    * @param size the size of that array, list or string
376    * @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size},
377    *     or if {@code end} is less than {@code start}
378    * @throws IllegalArgumentException if {@code size} is negative
379    */
380   public static void checkPositionIndexes(int start, int end, int size) {
381     // Carefully optimized for execution by hotspot (explanatory comment above)
382     if (start < 0 || end < start || end > size) {
383       throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
384     }
385   }
386 
387   private static String badPositionIndexes(int start, int end, int size) {
388     if (start < 0 || start > size) {
389       return badPositionIndex(start, size, "start index");
390     }
391     if (end < 0 || end > size) {
392       return badPositionIndex(end, size, "end index");
393     }
394     // end < start
395     return format("end index (%s) must not be less than start index (%s)", end, start);
396   }
397 
398   /**
399    * Substitutes each {@code %s} in {@code template} with an argument. These are matched by
400    * position: the first {@code %s} gets {@code args[0]}, etc.  If there are more arguments than
401    * placeholders, the unmatched arguments will be appended to the end of the formatted message in
402    * square braces.
403    *
404    * @param template a non-null string containing 0 or more {@code %s} placeholders.
405    * @param args the arguments to be substituted into the message template. Arguments are converted
406    *     to strings using {@link String#valueOf(Object)}. Arguments can be null.
407    */
408   // Note that this is somewhat-improperly used from Verify.java as well.
409   static String format(String template, @Nullable Object... args) {
410     template = String.valueOf(template); // null -> "null"
411 
412     // start substituting the arguments into the '%s' placeholders
413     StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
414     int templateStart = 0;
415     int i = 0;
416     while (i < args.length) {
417       int placeholderStart = template.indexOf("%s", templateStart);
418       if (placeholderStart == -1) {
419         break;
420       }
421       builder.append(template.substring(templateStart, placeholderStart));
422       builder.append(args[i++]);
423       templateStart = placeholderStart + 2;
424     }
425     builder.append(template.substring(templateStart));
426 
427     // if we run out of placeholders, append the extra args in square braces
428     if (i < args.length) {
429       builder.append(" [");
430       builder.append(args[i++]);
431       while (i < args.length) {
432         builder.append(", ");
433         builder.append(args[i++]);
434       }
435       builder.append(']');
436     }
437 
438     return builder.toString();
439   }
440 }